{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "iAtBbMoLtuJn"
   },
   "source": [
    "# 在本地训练 YOLOv8-OBB（C:\\\\Work\\\\Lab\\\\OBB_yolov8）\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "QsTjDixQr0DJ"
   },
   "source": [
    "训练 YOLOv8-OBB 模型，用于本地数据集 C:\\\\Work\\\\Lab\\\\OBB_yolov8 的旋转目标检测（OBB）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "^C\n"
     ]
    }
   ],
   "source": [
    "# Install a compatible PyTorch version\n",
    "!pip install torch==2.0.1 torchvision==0.15.2 --force-reinstall"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 6089,
     "status": "ok",
     "timestamp": 1737727601812,
     "user": {
      "displayName": "Shenzhe Zhu",
      "userId": "08240614809734426212"
     },
     "user_tz": -480
    },
    "id": "odbOXEtLosXN",
    "outputId": "aa60a3ad-ac36-40ee-e807-89e1846184a3"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: ultralytics in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (8.0.196)\n",
      "Requirement already satisfied: matplotlib>=3.3.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (3.9.2)\n",
      "Requirement already satisfied: numpy>=1.22.2 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (1.26.4)\n",
      "Requirement already satisfied: opencv-python>=4.6.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (4.9.0.80)\n",
      "Requirement already satisfied: pillow>=7.1.2 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (11.3.0)\n",
      "Requirement already satisfied: pyyaml>=5.3.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (6.0.2)\n",
      "Requirement already satisfied: requests>=2.23.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (2.32.3)\n",
      "Requirement already satisfied: scipy>=1.4.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (1.14.1)\n",
      "Requirement already satisfied: torch>=1.8.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (2.6.0)\n",
      "Requirement already satisfied: torchvision>=0.9.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (0.21.0)\n",
      "Requirement already satisfied: tqdm>=4.64.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (4.66.5)\n",
      "Requirement already satisfied: pandas>=1.1.4 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (2.2.3)\n",
      "Requirement already satisfied: seaborn>=0.11.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (0.13.2)\n",
      "Requirement already satisfied: psutil in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (6.0.0)\n",
      "Requirement already satisfied: py-cpuinfo in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (9.0.0)\n",
      "Requirement already satisfied: thop>=0.1.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from ultralytics) (0.1.1.post2209072238)\n",
      "Requirement already satisfied: contourpy>=1.0.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (1.3.0)\n",
      "Requirement already satisfied: cycler>=0.10 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (0.12.1)\n",
      "Requirement already satisfied: fonttools>=4.22.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (4.54.1)\n",
      "Requirement already satisfied: kiwisolver>=1.3.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (1.4.7)\n",
      "Requirement already satisfied: packaging>=20.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (24.1)\n",
      "Requirement already satisfied: pyparsing>=2.3.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (3.1.4)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from matplotlib>=3.3.0->ultralytics) (2.9.0.post0)\n",
      "Requirement already satisfied: pytz>=2020.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from pandas>=1.1.4->ultralytics) (2024.2)\n",
      "Requirement already satisfied: tzdata>=2022.7 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from pandas>=1.1.4->ultralytics) (2024.2)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from requests>=2.23.0->ultralytics) (3.4.0)\n",
      "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from requests>=2.23.0->ultralytics) (3.7)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from requests>=2.23.0->ultralytics) (2.2.3)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from requests>=2.23.0->ultralytics) (2024.8.30)\n",
      "Requirement already satisfied: filelock in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from torch>=1.8.0->ultralytics) (3.16.1)\n",
      "Requirement already satisfied: typing-extensions>=4.10.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from torch>=1.8.0->ultralytics) (4.12.2)\n",
      "Requirement already satisfied: networkx in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from torch>=1.8.0->ultralytics) (3.4)\n",
      "Requirement already satisfied: jinja2 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from torch>=1.8.0->ultralytics) (3.1.4)\n",
      "Requirement already satisfied: fsspec in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from torch>=1.8.0->ultralytics) (2024.10.0)\n",
      "Requirement already satisfied: sympy==1.13.1 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from torch>=1.8.0->ultralytics) (1.13.1)\n",
      "Requirement already satisfied: mpmath<1.4,>=1.1.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from sympy==1.13.1->torch>=1.8.0->ultralytics) (1.3.0)\n",
      "Requirement already satisfied: colorama in c:\\users\\shenz\\appdata\\roaming\\python\\python311\\site-packages (from tqdm>=4.64.0->ultralytics) (0.4.6)\n",
      "Requirement already satisfied: six>=1.5 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from python-dateutil>=2.7->matplotlib>=3.3.0->ultralytics) (1.16.0)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in c:\\users\\shenz\\appdata\\local\\programs\\python\\python311\\lib\\site-packages (from jinja2->torch>=1.8.0->ultralytics) (3.0.1)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n",
      "[notice] A new release of pip is available: 25.0.1 -> 25.2\n",
      "[notice] To update, run: python.exe -m pip install --upgrade pip\n"
     ]
    }
   ],
   "source": [
    "# 安装依赖（如已安装可跳过）\n",
    "!pip install ultralytics"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "executionInfo": {
     "elapsed": 636414,
     "status": "ok",
     "timestamp": 1737728247056,
     "user": {
      "displayName": "Shenzhe Zhu",
      "userId": "08240614809734426212"
     },
     "user_tz": -480
    },
    "id": "BfKwLXWOsl7W",
    "outputId": "edd863d2-0ba3-4c11-f503-b50e0c85852d"
   },
   "outputs": [
    {
     "ename": "UnpicklingError",
     "evalue": "Weights only load failed. This file can still be loaded, to do so you have two options, \u001b[1mdo those steps only if you trust the source of the checkpoint\u001b[0m. \n\t(1) In PyTorch 2.6, we changed the default value of the `weights_only` argument in `torch.load` from `False` to `True`. Re-running `torch.load` with `weights_only` set to `False` will likely succeed, but it can result in arbitrary code execution. Do it only if you got the file from a trusted source.\n\t(2) Alternatively, to load with `weights_only=True` please check the recommended steps in the following error message.\n\tWeightsUnpickler error: Unsupported global: GLOBAL ultralytics.nn.tasks.OBBModel was not an allowed global by default. Please use `torch.serialization.add_safe_globals([OBBModel])` or the `torch.serialization.safe_globals([OBBModel])` context manager to allowlist this global if you trust this class/function.\n\nCheck the documentation of torch.load to learn more about types accepted by default with weights_only https://pytorch.org/docs/stable/generated/torch.load.html.",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mUnpicklingError\u001b[0m                           Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[8], line 4\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01multralytics\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m YOLO\n\u001b[0;32m      3\u001b[0m \u001b[38;5;66;03m# 加载 OBB 模型（可选 yolov8n-obb.pt / yolov8s-obb.pt / yolov8m-obb.pt 等）\u001b[39;00m\n\u001b[1;32m----> 4\u001b[0m model \u001b[38;5;241m=\u001b[39m \u001b[43mYOLO\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mC:\u001b[39;49m\u001b[38;5;130;43;01m\\\\\u001b[39;49;00m\u001b[38;5;124;43mWork\u001b[39;49m\u001b[38;5;130;43;01m\\\\\u001b[39;49;00m\u001b[38;5;124;43mLab\u001b[39;49m\u001b[38;5;130;43;01m\\\\\u001b[39;49;00m\u001b[38;5;124;43myolov8n-obb.pt\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[0;32m      6\u001b[0m \u001b[38;5;66;03m# 训练（使用本地数据集 C:\\\\Work\\\\Lab\\\\OBB_yolov8）\u001b[39;00m\n\u001b[0;32m      7\u001b[0m results \u001b[38;5;241m=\u001b[39m model\u001b[38;5;241m.\u001b[39mtrain(\n\u001b[0;32m      8\u001b[0m     data\u001b[38;5;241m=\u001b[39m\u001b[38;5;124mr\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mC:\u001b[39m\u001b[38;5;130;01m\\\\\u001b[39;00m\u001b[38;5;124mWork\u001b[39m\u001b[38;5;130;01m\\\\\u001b[39;00m\u001b[38;5;124mLab\u001b[39m\u001b[38;5;130;01m\\\\\u001b[39;00m\u001b[38;5;124mOBB_yolov8\u001b[39m\u001b[38;5;130;01m\\\\\u001b[39;00m\u001b[38;5;124mdata.yaml\u001b[39m\u001b[38;5;124m\"\u001b[39m,  \u001b[38;5;66;03m# 数据配置文件\u001b[39;00m\n\u001b[0;32m      9\u001b[0m     epochs\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m100\u001b[39m,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m     14\u001b[0m     workers\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m4\u001b[39m,\n\u001b[0;32m     15\u001b[0m )\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\ultralytics\\engine\\model.py:97\u001b[0m, in \u001b[0;36mModel.__init__\u001b[1;34m(self, model, task)\u001b[0m\n\u001b[0;32m     95\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_new(model, task)\n\u001b[0;32m     96\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 97\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_load\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtask\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\ultralytics\\engine\\model.py:149\u001b[0m, in \u001b[0;36mModel._load\u001b[1;34m(self, weights, task)\u001b[0m\n\u001b[0;32m    147\u001b[0m suffix \u001b[38;5;241m=\u001b[39m Path(weights)\u001b[38;5;241m.\u001b[39msuffix\n\u001b[0;32m    148\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m suffix \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.pt\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m--> 149\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mckpt \u001b[38;5;241m=\u001b[39m \u001b[43mattempt_load_one_weight\u001b[49m\u001b[43m(\u001b[49m\u001b[43mweights\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    150\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtask \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39margs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtask\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[0;32m    151\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moverrides \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39margs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reset_ckpt_args(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39margs)\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\ultralytics\\nn\\tasks.py:628\u001b[0m, in \u001b[0;36mattempt_load_one_weight\u001b[1;34m(weight, device, inplace, fuse)\u001b[0m\n\u001b[0;32m    626\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mattempt_load_one_weight\u001b[39m(weight, device\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, inplace\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m, fuse\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m):\n\u001b[0;32m    627\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Loads a single model weights.\"\"\"\u001b[39;00m\n\u001b[1;32m--> 628\u001b[0m     ckpt, weight \u001b[38;5;241m=\u001b[39m \u001b[43mtorch_safe_load\u001b[49m\u001b[43m(\u001b[49m\u001b[43mweight\u001b[49m\u001b[43m)\u001b[49m  \u001b[38;5;66;03m# load ckpt\u001b[39;00m\n\u001b[0;32m    629\u001b[0m     args \u001b[38;5;241m=\u001b[39m {\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mDEFAULT_CFG_DICT, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m(ckpt\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtrain_args\u001b[39m\u001b[38;5;124m'\u001b[39m, {}))}  \u001b[38;5;66;03m# combine model and default args, preferring model args\u001b[39;00m\n\u001b[0;32m    630\u001b[0m     model \u001b[38;5;241m=\u001b[39m (ckpt\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mema\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m ckpt[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmodel\u001b[39m\u001b[38;5;124m'\u001b[39m])\u001b[38;5;241m.\u001b[39mto(device)\u001b[38;5;241m.\u001b[39mfloat()  \u001b[38;5;66;03m# FP32 model\u001b[39;00m\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\ultralytics\\nn\\tasks.py:567\u001b[0m, in \u001b[0;36mtorch_safe_load\u001b[1;34m(weight)\u001b[0m\n\u001b[0;32m    562\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m    563\u001b[0m     \u001b[38;5;28;01mwith\u001b[39;00m temporary_modules({\n\u001b[0;32m    564\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.yolo.utils\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.utils\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m    565\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.yolo.v8\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.models.yolo\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m    566\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.yolo.data\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.data\u001b[39m\u001b[38;5;124m'\u001b[39m}):  \u001b[38;5;66;03m# for legacy 8.0 Classify and Pose models\u001b[39;00m\n\u001b[1;32m--> 567\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mtorch\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmap_location\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mcpu\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m, file  \u001b[38;5;66;03m# load\u001b[39;00m\n\u001b[0;32m    569\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mModuleNotFoundError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:  \u001b[38;5;66;03m# e.name is missing module name\u001b[39;00m\n\u001b[0;32m    570\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m e\u001b[38;5;241m.\u001b[39mname \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmodels\u001b[39m\u001b[38;5;124m'\u001b[39m:\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\torch\\serialization.py:1470\u001b[0m, in \u001b[0;36mload\u001b[1;34m(f, map_location, pickle_module, weights_only, mmap, **pickle_load_args)\u001b[0m\n\u001b[0;32m   1462\u001b[0m                 \u001b[38;5;28;01mreturn\u001b[39;00m _load(\n\u001b[0;32m   1463\u001b[0m                     opened_zipfile,\n\u001b[0;32m   1464\u001b[0m                     map_location,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m   1467\u001b[0m                     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mpickle_load_args,\n\u001b[0;32m   1468\u001b[0m                 )\n\u001b[0;32m   1469\u001b[0m             \u001b[38;5;28;01mexcept\u001b[39;00m pickle\u001b[38;5;241m.\u001b[39mUnpicklingError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m-> 1470\u001b[0m                 \u001b[38;5;28;01mraise\u001b[39;00m pickle\u001b[38;5;241m.\u001b[39mUnpicklingError(_get_wo_message(\u001b[38;5;28mstr\u001b[39m(e))) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m   1471\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m _load(\n\u001b[0;32m   1472\u001b[0m             opened_zipfile,\n\u001b[0;32m   1473\u001b[0m             map_location,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m   1476\u001b[0m             \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mpickle_load_args,\n\u001b[0;32m   1477\u001b[0m         )\n\u001b[0;32m   1478\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m mmap:\n",
      "\u001b[1;31mUnpicklingError\u001b[0m: Weights only load failed. This file can still be loaded, to do so you have two options, \u001b[1mdo those steps only if you trust the source of the checkpoint\u001b[0m. \n\t(1) In PyTorch 2.6, we changed the default value of the `weights_only` argument in `torch.load` from `False` to `True`. Re-running `torch.load` with `weights_only` set to `False` will likely succeed, but it can result in arbitrary code execution. Do it only if you got the file from a trusted source.\n\t(2) Alternatively, to load with `weights_only=True` please check the recommended steps in the following error message.\n\tWeightsUnpickler error: Unsupported global: GLOBAL ultralytics.nn.tasks.OBBModel was not an allowed global by default. Please use `torch.serialization.add_safe_globals([OBBModel])` or the `torch.serialization.safe_globals([OBBModel])` context manager to allowlist this global if you trust this class/function.\n\nCheck the documentation of torch.load to learn more about types accepted by default with weights_only https://pytorch.org/docs/stable/generated/torch.load.html."
     ]
    }
   ],
   "source": [
    "from ultralytics import YOLO\n",
    "\n",
    "# 加载 OBB 模型（可选 yolov8n-obb.pt / yolov8s-obb.pt / yolov8m-obb.pt 等）\n",
    "model = YOLO(\"C:\\\\Work\\\\Lab\\\\yolov8n-obb.pt\")\n",
    "\n",
    "# 训练（使用本地数据集 C:\\\\Work\\\\Lab\\\\OBB_yolov8）\n",
    "results = model.train(\n",
    "    data=r\"C:\\\\Work\\\\Lab\\\\OBB_yolov8\\\\data.yaml\",  # 数据配置文件\n",
    "    epochs=100,\n",
    "    batch=16,\n",
    "    imgsz=640,\n",
    "    project=r\"C:\\\\Work\\\\Lab\\\\runs_obb\",\n",
    "    name=\"yolov8_obb_local\",\n",
    "    workers=4,\n",
    ")\n",
    "\n",
    "print(getattr(results, 'save_dir', None))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 439
    },
    "executionInfo": {
     "elapsed": 1793,
     "status": "ok",
     "timestamp": 1737729894312,
     "user": {
      "displayName": "Shenzhe Zhu",
      "userId": "08240614809734426212"
     },
     "user_tz": -480
    },
    "id": "F5VWD0-0sfNY",
    "outputId": "cbe5742b-cfa0-4688-d9b2-f3322f6246aa"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "使用图片: C:\\Work\\Lab\\realsense_20250618_095811_png.rf.ccf3f7a4d78ba11c87b904967babcc23.jpg\n"
     ]
    },
    {
     "ename": "UnpicklingError",
     "evalue": "Weights only load failed. This file can still be loaded, to do so you have two options, \u001b[1mdo those steps only if you trust the source of the checkpoint\u001b[0m. \n\t(1) In PyTorch 2.6, we changed the default value of the `weights_only` argument in `torch.load` from `False` to `True`. Re-running `torch.load` with `weights_only` set to `False` will likely succeed, but it can result in arbitrary code execution. Do it only if you got the file from a trusted source.\n\t(2) Alternatively, to load with `weights_only=True` please check the recommended steps in the following error message.\n\tWeightsUnpickler error: Unsupported global: GLOBAL ultralytics.nn.tasks.OBBModel was not an allowed global by default. Please use `torch.serialization.add_safe_globals([OBBModel])` or the `torch.serialization.safe_globals([OBBModel])` context manager to allowlist this global if you trust this class/function.\n\nCheck the documentation of torch.load to learn more about types accepted by default with weights_only https://pytorch.org/docs/stable/generated/torch.load.html.",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mUnpicklingError\u001b[0m                           Traceback (most recent call last)",
      "Cell \u001b[1;32mIn[4], line 17\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m sample\u001b[38;5;241m.\u001b[39mexists(), \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m指定图片不存在: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msample\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m     15\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m使用图片: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00msample\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m---> 17\u001b[0m model \u001b[38;5;241m=\u001b[39m \u001b[43mYOLO\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mbest\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m     18\u001b[0m results \u001b[38;5;241m=\u001b[39m model(source\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mstr\u001b[39m(sample), conf\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m0.5\u001b[39m)  \u001b[38;5;66;03m# 设置置信度阈值\u001b[39;00m\n\u001b[0;32m     20\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m r \u001b[38;5;129;01min\u001b[39;00m results:\n\u001b[0;32m     21\u001b[0m     \u001b[38;5;66;03m# 显示检测信息\u001b[39;00m\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\ultralytics\\engine\\model.py:97\u001b[0m, in \u001b[0;36mModel.__init__\u001b[1;34m(self, model, task)\u001b[0m\n\u001b[0;32m     95\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_new(model, task)\n\u001b[0;32m     96\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m---> 97\u001b[0m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_load\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtask\u001b[49m\u001b[43m)\u001b[49m\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\ultralytics\\engine\\model.py:149\u001b[0m, in \u001b[0;36mModel._load\u001b[1;34m(self, weights, task)\u001b[0m\n\u001b[0;32m    147\u001b[0m suffix \u001b[38;5;241m=\u001b[39m Path(weights)\u001b[38;5;241m.\u001b[39msuffix\n\u001b[0;32m    148\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m suffix \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m.pt\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m--> 149\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mckpt \u001b[38;5;241m=\u001b[39m \u001b[43mattempt_load_one_weight\u001b[49m\u001b[43m(\u001b[49m\u001b[43mweights\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m    150\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtask \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39margs[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtask\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[0;32m    151\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39moverrides \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39margs \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reset_ckpt_args(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39margs)\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\ultralytics\\nn\\tasks.py:628\u001b[0m, in \u001b[0;36mattempt_load_one_weight\u001b[1;34m(weight, device, inplace, fuse)\u001b[0m\n\u001b[0;32m    626\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mattempt_load_one_weight\u001b[39m(weight, device\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, inplace\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m, fuse\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m):\n\u001b[0;32m    627\u001b[0m \u001b[38;5;250m    \u001b[39m\u001b[38;5;124;03m\"\"\"Loads a single model weights.\"\"\"\u001b[39;00m\n\u001b[1;32m--> 628\u001b[0m     ckpt, weight \u001b[38;5;241m=\u001b[39m \u001b[43mtorch_safe_load\u001b[49m\u001b[43m(\u001b[49m\u001b[43mweight\u001b[49m\u001b[43m)\u001b[49m  \u001b[38;5;66;03m# load ckpt\u001b[39;00m\n\u001b[0;32m    629\u001b[0m     args \u001b[38;5;241m=\u001b[39m {\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mDEFAULT_CFG_DICT, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m(ckpt\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtrain_args\u001b[39m\u001b[38;5;124m'\u001b[39m, {}))}  \u001b[38;5;66;03m# combine model and default args, preferring model args\u001b[39;00m\n\u001b[0;32m    630\u001b[0m     model \u001b[38;5;241m=\u001b[39m (ckpt\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mema\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m ckpt[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmodel\u001b[39m\u001b[38;5;124m'\u001b[39m])\u001b[38;5;241m.\u001b[39mto(device)\u001b[38;5;241m.\u001b[39mfloat()  \u001b[38;5;66;03m# FP32 model\u001b[39;00m\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\ultralytics\\nn\\tasks.py:567\u001b[0m, in \u001b[0;36mtorch_safe_load\u001b[1;34m(weight)\u001b[0m\n\u001b[0;32m    562\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m    563\u001b[0m     \u001b[38;5;28;01mwith\u001b[39;00m temporary_modules({\n\u001b[0;32m    564\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.yolo.utils\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.utils\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m    565\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.yolo.v8\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.models.yolo\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m    566\u001b[0m             \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.yolo.data\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124multralytics.data\u001b[39m\u001b[38;5;124m'\u001b[39m}):  \u001b[38;5;66;03m# for legacy 8.0 Classify and Pose models\u001b[39;00m\n\u001b[1;32m--> 567\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mtorch\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfile\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmap_location\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mcpu\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m, file  \u001b[38;5;66;03m# load\u001b[39;00m\n\u001b[0;32m    569\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mModuleNotFoundError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:  \u001b[38;5;66;03m# e.name is missing module name\u001b[39;00m\n\u001b[0;32m    570\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m e\u001b[38;5;241m.\u001b[39mname \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmodels\u001b[39m\u001b[38;5;124m'\u001b[39m:\n",
      "File \u001b[1;32mc:\\Users\\Shenz\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\torch\\serialization.py:1470\u001b[0m, in \u001b[0;36mload\u001b[1;34m(f, map_location, pickle_module, weights_only, mmap, **pickle_load_args)\u001b[0m\n\u001b[0;32m   1462\u001b[0m                 \u001b[38;5;28;01mreturn\u001b[39;00m _load(\n\u001b[0;32m   1463\u001b[0m                     opened_zipfile,\n\u001b[0;32m   1464\u001b[0m                     map_location,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m   1467\u001b[0m                     \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mpickle_load_args,\n\u001b[0;32m   1468\u001b[0m                 )\n\u001b[0;32m   1469\u001b[0m             \u001b[38;5;28;01mexcept\u001b[39;00m pickle\u001b[38;5;241m.\u001b[39mUnpicklingError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m-> 1470\u001b[0m                 \u001b[38;5;28;01mraise\u001b[39;00m pickle\u001b[38;5;241m.\u001b[39mUnpicklingError(_get_wo_message(\u001b[38;5;28mstr\u001b[39m(e))) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m   1471\u001b[0m         \u001b[38;5;28;01mreturn\u001b[39;00m _load(\n\u001b[0;32m   1472\u001b[0m             opened_zipfile,\n\u001b[0;32m   1473\u001b[0m             map_location,\n\u001b[1;32m   (...)\u001b[0m\n\u001b[0;32m   1476\u001b[0m             \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mpickle_load_args,\n\u001b[0;32m   1477\u001b[0m         )\n\u001b[0;32m   1478\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m mmap:\n",
      "\u001b[1;31mUnpicklingError\u001b[0m: Weights only load failed. This file can still be loaded, to do so you have two options, \u001b[1mdo those steps only if you trust the source of the checkpoint\u001b[0m. \n\t(1) In PyTorch 2.6, we changed the default value of the `weights_only` argument in `torch.load` from `False` to `True`. Re-running `torch.load` with `weights_only` set to `False` will likely succeed, but it can result in arbitrary code execution. Do it only if you got the file from a trusted source.\n\t(2) Alternatively, to load with `weights_only=True` please check the recommended steps in the following error message.\n\tWeightsUnpickler error: Unsupported global: GLOBAL ultralytics.nn.tasks.OBBModel was not an allowed global by default. Please use `torch.serialization.add_safe_globals([OBBModel])` or the `torch.serialization.safe_globals([OBBModel])` context manager to allowlist this global if you trust this class/function.\n\nCheck the documentation of torch.load to learn more about types accepted by default with weights_only https://pytorch.org/docs/stable/generated/torch.load.html."
     ]
    }
   ],
   "source": [
    "# 使用训练得到的模型进行本地推理示例\n",
    "from ultralytics import YOLO\n",
    "from PIL import Image\n",
    "import matplotlib.pyplot as plt\n",
    "from pathlib import Path\n",
    "\n",
    "# 结果权重路径（如名称或project有改动，请同步修改）\n",
    "best = Path(r\"C:\\\\Work\\\\Lab\\\\runs_obb\\\\yolov8_obb_local\\\\weights\\\\best.pt\")\n",
    "assert best.exists(), f\"best.pt 不存在: {best}\"\n",
    "\n",
    "# 使用指定的图片进行演示\n",
    "sample = Path(r\"C:\\Work\\Lab\\realsense_20250618_095811_png.rf.ccf3f7a4d78ba11c87b904967babcc23.jpg\")\n",
    "assert sample.exists(), f\"指定图片不存在: {sample}\"\n",
    "\n",
    "print(f\"使用图片: {sample}\")\n",
    "\n",
    "model = YOLO(str(best))\n",
    "results = model(source=str(sample), conf=0.5)  # 设置置信度阈值\n",
    "\n",
    "for r in results:\n",
    "    # 显示检测信息\n",
    "    print(f\"检测到 {len(r.obb)} 个目标\" if r.obb is not None else \"未检测到目标\")\n",
    "    \n",
    "        # 绘制带有边界框的图像\n",
    "    im_array = r.plot(\n",
    "        conf=True,      # 显示置信度\n",
    "        labels=True,    # 显示标签\n",
    "        boxes=True,     # 显示边界框\n",
    "        line_width=2    # 边界框线宽\n",
    "    )\n",
    "    \n",
    "    # 如果有检测结果，在图像上添加角度信息\n",
    "    if r.obb is not None and hasattr(r.obb, 'xywhr'):\n",
    "        import cv2\n",
    "        import numpy as np\n",
    "        \n",
    "        for i, (xywhr, conf, cls) in enumerate(zip(r.obb.xywhr, r.obb.conf, r.obb.cls)):\n",
    "            x_center, y_center, width, height, angle_rad = xywhr\n",
    "\n",
    "            angle_deg = float(angle_rad * 180 / np.pi)  # 转换为度数\n",
    "            if width>height :\n",
    "                angle_deg = angle_deg + 90\n",
    "            print(angle_deg, width, height, x_center, y_center)\n",
    "            # 在图像上添加角度文本\n",
    "            angle_text = f\"{angle_deg:.1f} deg\"\n",
    "            text_position = (int(x_center), int(y_center - height/2 - 20))  # 在边界框上方显示角度\n",
    "            # 在中心点绘制圆圈\n",
    "            center_point = (int(x_center), int(y_center))\n",
    "            cv2.circle(im_array, center_point, 5, (0, 0, 255), -1)  # 红色实心圆\n",
    "\n",
    "            \n",
    "            # 添加角度文本到图像\n",
    "            cv2.putText(im_array, angle_text, text_position, \n",
    "                       cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 255), 2)  # 黄色文字\n",
    "    \n",
    "    # 转换为RGB并显示\n",
    "    im = Image.fromarray(im_array[..., ::-1])  # BGR转RGB\n",
    "    \n",
    "    # 创建更大的图像显示\n",
    "    plt.figure(figsize=(12, 8))\n",
    "    plt.imshow(im)\n",
    "    plt.axis('off')\n",
    "    plt.title(f\"YOLOv8-OBB 检测结果 - {sample.name}\")\n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    \n",
    "    # 打印详细检测信息\n",
    "    if r.obb is not None:\n",
    "        for i, (box, conf, cls) in enumerate(zip(r.obb.xyxyxyxy, r.obb.conf, r.obb.cls)):\n",
    "            class_name = model.names[int(cls)]\n",
    "            \n",
    "            # 获取角度信息\n",
    "            if hasattr(r.obb, 'xywhr'):\n",
    "                angle_rad = r.obb.xywhr[i][4]\n",
    "                angle_deg = float(angle_rad * 180 / np.pi)\n",
    "                print(f\"目标 {i+1}: {class_name}, 置信度: {conf:.3f}, 角度: {angle_deg:.1f}\")\n",
    "            else:\n",
    "                print(f\"目标 {i+1}: {class_name}, 置信度: {conf:.3f}\")"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "authorship_tag": "ABX9TyNAnMFuDjvf7HyKzfeN8fmz",
   "gpuType": "A100",
   "machine_shape": "hm",
   "mount_file_id": "1aLVse__OE8-2J_J38yH03DCnlBI4MHgl",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
